<?php
/**
 * Easthv Zend Framework Project
 *
 * LICENSE:
 *
 * @category   Zend
 * @package    Zend_Easthv
 * @copyright  Copyright (c) 2009-2010 Easthv Team @ East Hui Van Business Consulting Co., Ltd.(http://www.easthv.com)
 * @license    http://framework.zend.com/license/   BSD License
 * @version    1.0
 * @link       http://www.easthv.com
 * @since      1.0
*/

/**
 * Array class
 *
 * @category   Zend
 * @package    Zend_Easthv
 * @copyright  Copyright (c) 2009-2010 Easthv Team @ East Hui Van Business Consulting Co., Ltd.(http://www.easthv.com)
 * @license    http://framework.zend.com/license/   BSD License
 * @version    1.0
 * @link       http://www.easthv.com
 * @since      1.0
 * @deprecated
 */
class Zend_Easthv_Encryptstring
{
	protected static $_hexCHS = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz$_~';

	protected static $_key = array(48,38,26,11,18,19,55,58,10,33,34,49,14,25,44,52,61,2,56,16,23,9,45,29,3,12,39,30,42,47,22,21,60,1,54,28,57,17,27,15,40,46,43,13,0,51,35,63,36,50,6,32,24,31,62,5,4,8,53,59,41,20,37,7);

	protected static $_hexTBL = array(
        '0'=>0, '1'=>1, '2'=>2, '3'=>3, '4'=>4, '5'=>5, '6'=>6, '7'=>7, '8'=>8, '9'=>9,
        'A'=>10, 'B'=>11, 'C'=>12, 'D'=>13, 'E'=>14, 'F'=>15, 'G'=>16, 'H'=>17, 'I'=>18, 'J'=>19,
        'K'=>20, 'L'=>21, 'M'=>22, 'N'=>23, 'O'=>24, 'P'=>25, 'Q'=>26, 'R'=>27, 'S'=>28, 'T'=>29,
        'U'=>30, 'V'=>31, 'W'=>32, 'X'=>33, 'Y'=>34, 'Z'=>35, 'a'=>36, 'b'=>37, 'c'=>38, 'd'=>39,
        'e'=>40, 'f'=>41, 'g'=>42, 'h'=>43, 'i'=>44, 'j'=>45, 'k'=>46, 'l'=>47, 'm'=>48, 'n'=>49,
        'o'=>50, 'p'=>51, 'q'=>52, 'r'=>53, 's'=>54, 't'=>55, 'u'=>56, 'v'=>57, 'w'=>58, 'x'=>59,
        'y'=>60, 'z'=>61,
        '$'=>62, '_'=>63, '~'=>64  // pad
	);	
	
	protected static $_k16;
	protected static $_k41;
	protected static $_ks;
	protected static $_sz;
	protected static $_cnt;
	protected static $_t16;
	protected static $_t41;
		
	//
    // 进制转换加密法
    // 原理：
    // 用 [0-9A-Za-z] 62 个字符的随机排列作为进制表对字符的值进行转换。
    // 特点：
    // 1. 密文为数字和大小写英文字母，及原有的 [\s\n\r]；
    // 2. 增加了密文字符的平移操作，提高加密强度；
    // 3. 可自动识别单双字节字符并进行相应编码；
    // 4. 双字节字符用 3 位 41 进制表示，最大可表示 68920 的字值；
    // 5. 单字节字符用 2 位 16 进制表示，最大可表示 255 的字值；
    // 6. 空白、换行和回车 [\s\n\r] 保持原样。
    // 缺点：
    // 密文会比原文长，中文视宽增长 1.5 倍（一个汉字算 2 字节宽）；
    // 考虑空白和换行/回车不处理，英文增长 < 2 倍。
    // 推荐：
    // 可用于任意类型的文本加密，由于密文为规范的 [\w]，适于各类环境。
    //
    // 参数：
    // key[0-57) 间的值小于 62 且唯一，其后的值可任意和重复；
    // key[0-16) 为 16 进制字符表，key[16-57) 为 41 进制字符表。
    //
    // @param array key  - [0-61] 互斥值数组，length >= 57
    //
    public static function set($key = null)
    {
		if (!$key) {
			$key = self::$_key;
		}
		
		$hexCHS = self::$_hexCHS;
		
		if (count($key) < 57) {
            echo 'the key is too short.';
        }
        // 平移密钥
        self::$_sz = self::charCodeAt($key[15], $hexCHS) % (count($key)-20) + 10;
        self::$_ks = self::slice(self::$_sz, $key);

		for ($i=0; $i<self::$_sz; ++$i) {
            self::$_ks[$i] = self::charCodeAt(self::$_ks[$i]%62, $hexCHS);
        }

		self::$_k16 = array(); 
		self::$_k41 = array();
		self::$_t16 = array(); 
		self::$_t41 = array();

        for ($i=0; $i<16; ++$i) {
            self::$_k16[$i] = substr($hexCHS, $key[$i], 1);
            self::$_t16[self::$_k16[$i]] = $i;
        }
		
		for ($i=0; $i<41; ++$i) {
            self::$_k41[$i] = substr($hexCHS, $key[$i+16], 1);
            self::$_t41[self::$_k41[$i]] = $i;
        }

	}
	
	protected static function _encodeOne($s)
	{
       $n = self::charCodeAt(0, $s[0]);

	   if ($n <= 0xff) {
		   return self::$_k16[self::parseInt($n/16)] . self::$_k16[$n%16];
	   } else {
		   return self::$_k41[self::parseInt($n/1681)] . self::$_k41[self::parseInt($n%1681/41)] . self::$_k41[$n%41];
	   }

	}
	
	protected static function _encodeTwo($s)
	{
		$res = substr(self::$_hexCHS,(self::$_hexTBL[$s[0]] + self::$_ks[self::$_cnt++%self::$_sz]) % 62,1);
	
		return $res;
	}
	
	protected static function _decodeOne($s)
	{
		return $res = substr(self::$_hexCHS,(self::$_hexTBL[$s[0]] - self::$_ks[self::$_cnt++%self::$_sz]%62 + 62) % 62,1);
	}
	
	// 加密
	public static function encode($s)
	{
		self::set();
		
		self::$_cnt = 0;
	
		$s = preg_replace_callback('/[^\s\n\r]/', array( self, '_encodeOne'), $s);
		
		$s = preg_replace_callback('/[0-9A-Za-z]/', array( self, '_encodeTwo'), $s);
		
		return $s;
	}

	// 解密
	public static function decode($s)
	{
		self::set();
		
		self::$_cnt = 0;

		$string = preg_replace_callback('/[0-9A-Za-z]/', array( self, '_decodeOne'), $s);

		$res = '';
		
		for ($i=0; $i<strlen($string);) {
			$ch = substr($string, $i, 1);
			
			if (preg_match('/[\s\n\r]/', $ch)) {
				$res .= $ch;
				++$i;
			} else if (self::$_t16[$ch]) {
				$res .= self::fromCharCode(self::$_t16[substr($string, $i, 1)]*16 + self::$_t16[substr($string, $i+1, 1)]);
				$i += 2;
			} else {
				$res .= self::fromCharCode(self::$_t41[substr($string, $i, 1)]*1681 + self::$_t41[substr($string, $i+1, 1)]*41 + self::$_t41[substr($string, $i+2, 1)]);
                $i += 3;
            }
        }

		return  $res;
	}
	
	public static function slice($start, $arr)
	{
		$num = count($arr);	

		if (!$num) {
			return array();
		}
	
		$res = array();

		foreach ($arr as $key=>$val) {
			if ($key >= ($num - $start)) {
				$res[] = $val;
			}
		}
		
		return $res;
	}
	
	public static function charCodeAt($start, $string) 
	{
		return self::getUnicodeFromOneUTF8(substr($string, $start, 1));
	}
	
	public function parseInt($string) 
	{
		//	return intval($string);
		if(preg_match('/(\d+)/', $string, $array)) {
			return $array[1];
		} else {
			return 0;
		}
	}
	
	/*
	 * php里有个chr()函数将ancii码转为字符，以下是套用php手册中提供的代码修改后封装的一个fromCharCode()函数
	 *
	 */
	public static function fromCharCode($codes) 
	{
		if (is_scalar($codes)) {	
			$codes= func_get_args();
		}

		$str= '';

		foreach ($codes as $code) {
			
			$str.= chr($code);
		}

		return $str;
	}

	public static function getUnicodeFromOneUTF8($word) 
	{
		//获取其字符的内部数组表示，所以本文件应用utf-8编码！
		if (is_array( $word))
			$arr = $word;
		else 
			$arr = str_split($word);
		//此时，$arr应类似array(228, 189, 160)
		//定义一个空字符串存储
		$bin_str = '';
		//转成数字再转成二进制字符串，最后联合起来。
		foreach ($arr as $value)
			$bin_str .= decbin(ord($value));
		//此时，$bin_str应类似111001001011110110100000,如果是汉字"你"
		//正则截取
		$bin_str = preg_replace('/^.{4}(.{4}).{2}(.{6}).{2}(.{6})$/','$1$2$3', $bin_str);
		//此时， $bin_str应类似0100111101100000,如果是汉字"你"
		return bindec($bin_str); //返回类似20320，汉字"你"
		//return dechex(bindec($bin_str)); //如想返回十六进制4f60，用这句
	}
}
